import { isObject } from '@vue/shared'
import * as CryptoJS from 'crypto-js'
import { UseAuthority } from '@/stores/permissionPrompt.ts'

// import { useAppStore } from '@/stores/app'
// import { TUITranslateService } from '@tencentcloud/chat-uikit-engine'
// import { Languages } from '@/types/languages'

// const appStore = useAppStore()
/**
 * @description 获取元素节点信息（在组件中的元素必须要传ctx）
 * @param  { String } selector 选择器 '.app' | '#app'
 * @param  { Boolean } all 是否多选
 * @param  { ctx } context 当前组件实例
 */
export const getRect = (selector: string, all = false, context?: any) => {
    return new Promise((resolve, reject) => {
        let query = uni.createSelectorQuery()
        if (context) {
            query = uni.createSelectorQuery().in(context)
        }
        query[all ? 'selectAll' : 'select'](selector)
            .boundingClientRect(function (rect) {
                if (all && Array.isArray(rect) && rect.length) {
                    return resolve(rect)
                }
                if (!all && rect) {
                    return resolve(rect)
                }
                reject('找不到元素')
            })
            .exec()
    })
}

/**
 * @description 获取当前页面实例
 */
export function currentPage() {
    const pages = getCurrentPages()
    const currentPage = pages[pages.length - 1]
    return currentPage || {}
}

/**
 * @description 后台选择链接专用跳转
 */
interface Link {
    path: string
    name?: string
    type: string
    isTab: boolean
    query?: Record<string, any>
}

export enum LinkTypeEnum {
    'SHOP_PAGES' = 'shop',
    'CUSTOM_LINK' = 'custom'
}

export function navigateTo(link: Link, navigateType: 'navigateTo' | 'reLaunch' = 'navigateTo') {
    const url = link.query ? `${link.path}?${objectToQuery(link.query)}` : link.path
    navigateType == 'navigateTo' && uni.navigateTo({ url })
    navigateType == 'reLaunch' && uni.reLaunch({ url })
}

/**
 * @description 是否为空
 * @param {unknown} value
 * @return {Boolean}
 */
export const isEmpty = (value: unknown) => {
    return value == null && typeof value == 'undefined'
}

/**
 * @description 对象格式化为Query语法
 * @param { Object } params
 * @return {string} Query语法
 */
export function objectToQuery(params: Record<string, any>): string {
    let query = ''
    for (const props of Object.keys(params)) {
        const value = params[props]
        const part = encodeURIComponent(props) + '='
        if (!isEmpty(value)) {
            console.log(encodeURIComponent(props), isObject(value))
            if (isObject(value)) {
                for (const key of Object.keys(value)) {
                    if (!isEmpty(value[key])) {
                        const params = props + '[' + key + ']'
                        const subPart = encodeURIComponent(params) + '='
                        query += subPart + encodeURIComponent(value[key]) + '&'
                    }
                }
            } else {
                query += part + encodeURIComponent(value) + '&'
            }
        }
    }
    return query.slice(0, -1)
}

/**
 * @description 格式化输出价格
 * @param  { string } price 价格
 * @param  { string } take 小数点操作
 * @param  { string } prec 小数位补
 */
export function formatPrice({ price, take = 'all', prec = undefined }: any) {
    let [integer, decimals = ''] = (price + '').split('.')

    // 小数位补
    if (prec !== undefined) {
        const LEN = decimals.length
        for (let i = prec - LEN; i > 0; --i) decimals += '0'
        decimals = decimals.substr(0, prec)
    }

    switch (take) {
        case 'int':
            return integer
        case 'dec':
            return decimals
        case 'all':
            return integer + '.' + decimals
    }
}

/**
 * @description 组合异步任务
 * @param  { string } task 异步任务
 */

export function series(...task: Array<(_arg: any) => any>) {
    return function (): Promise<any> {
        return new Promise((resolve, reject) => {
            const iteratorTask = task.values()
            const next = (res?: any) => {
                const nextTask = iteratorTask.next()
                if (nextTask.done) {
                    resolve(res)
                } else {
                    Promise.resolve(nextTask.value(res)).then(next).catch(reject)
                }
            }
            next()
        })
    }
}

/**
 * @description 添加单位
 * @param {String | Number} value 值 100
 * @param {String} unit 单位 px em rem
 */
export const addUnit = (value: string | number, unit = 'rpx') => {
    return !Object.is(Number(value), NaN) ? `${value}${unit}` : value
}

/**
 * 自动适配不同的后端架构
 * 1. 例如 /act/oa/task ,在微服务架构保持不变,在单体架构编程 /admin/oa/task
 * 2. 特殊 /gen/xxx ,在微服务架构、单体架构编程 都需保持不变
 *
 * @param originUrl 原始路径
 */
export const adaptationUrl = (originUrl?: string) => {
    // 微服务架构 不做路径转换,为空不做路径转换
    const isMicro = import.meta.env.VITE_IS_MICRO
    if (isEmpty(isMicro) || isMicro === 'true') {
        return originUrl
    }

    // 验证码服务
    if (originUrl?.startsWith('/code/')) {
        return `/admin${originUrl}`
    }

    // 如果是代码生成服务，不做路径转换
    if (originUrl?.startsWith('/gen')) {
        return originUrl
    }
    // 如果是支付接口，不做路径转换
    if (originUrl?.startsWith('/admin/m/order/pay')) {
        return originUrl
    }
    // 转为 /admin 路由前缀的请求
    return `/admin/${originUrl?.split('/').splice(2).join('/')}`
}

/**
 *加密处理
 */

export function encryption(src: string, keyWord: string) {
    const key = CryptoJS.enc.Utf8.parse(keyWord)

    // 加密
    const encrypted = CryptoJS.AES.encrypt(src, key, {
        iv: key,
        mode: CryptoJS.mode.CFB,
        padding: CryptoJS.pad.NoPadding
    })
    return encrypted.toString()
}

// 解密
// 解密函数
export function decryption(encryptedStr: string, keyWord: string) {
    const key = CryptoJS.enc.Utf8.parse(keyWord)
    const encrypted = CryptoJS.enc.Base64.parse(encryptedStr)
    const src = CryptoJS.enc.Base64.stringify(encrypted)

    // 解密
    const decrypted = CryptoJS.AES.decrypt(src, key, {
        iv: key,
        mode: CryptoJS.mode.CFB,
        padding: CryptoJS.pad.NoPadding
    })

    return decrypted.toString(CryptoJS.enc.Utf8)
}

/**
 *加密处理
 */
export function encryptionBase64(rawStr: string) {
    const wordArray = CryptoJS.enc.Utf8.parse(rawStr)
    return CryptoJS.enc.Base64.stringify(wordArray)
}

/**
 * 获取顶部状态栏高度
 */
export const statusBarHeightFn = () => {
    let statusBar = ''
    uni.getSystemInfo({
        success: (e) => {
            statusBar = e.statusBarHeight!.toString() //状态栏高度
        }
    })
    return statusBar
}

type amountType = '$' | '€' | '£' | '¥'
// 货币符号
export const currencySymbol: amountType = '$'

/**
 * 格式化金额
 * @param number
 * @param decimals
 * @param decPoint
 * @param thousandsSep
 * @param roundTag
 */
export const formatAmount = (
    number: number | string,
    decimals = 2,
    decPoint = '.',
    thousandsSep = ',',
    roundTag = 'round'
) => {
    number = (number + '').replace(/[^0-9+-Ee.]/g, '')
    roundTag = roundTag || 'ceil' // "ceil","floor","round"
    const n = !isFinite(+number) ? 0 : +number
    const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals)
    let s = ''
    const toFixedFix = function (n: number, prec: number) {
        const k = Math.pow(10, prec)
        return (
            '' +
            parseFloat(Math[roundTag](parseFloat((n * k).toFixed(prec * 2))).toFixed(prec * 2)) / k
        )
    }
    s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.')
    if (thousandsSep) {
        const re = /(-?\d+)(\d{3})/
        while (re.test(s[0])) {
            s[0] = s[0].replace(re, `$1${thousandsSep}$2`)
        }
    }

    if ((s[1] || '').length < prec) {
        s[1] = s[1] || ''
        s[1] += new Array(prec - s[1].length + 1).join('0')
    }
    return s.join(decPoint)
}

/**
 * 金额格式化
 * @param amount
 * @param sign
 */
export const amountFormat = (amount: number, sign = '') => {
    let val
    if (amount || amount === 0) {
        val = `${currencySymbol}${sign}${formatAmount(amount)}`
    } else {
        val = '-'
    }
    // console.log(`origin val: ${amount} -> format val: ${val}, typeof: ${typeof val}, sign: ${sign}`)
    return val
}

// 状态格式化
export const stateFormat = (
    val: any,
    list: Array<any> = [],
    prop: object = { value: 'value', label: 'text' }
) => {
    if (val === undefined || val === null || val === '') {
        return ''
    }

    const find = (list || []).find((item) => Number(item[prop.value]) == Number(val))
    return find ? find[prop.label] : ''
}

// 语言格式化
export interface I18n {
    zh?: string
    cn?: string
    en?: string
    fr?: string
    de?: string
    es?: string
    fa?: string
    hr?: string
    it?: string
    ja?: string
    kr?: string
    nl?: string
    tr?: string
    pt?: string
    ptBR?: string
}
export const langFormat = (val: I18n) => {
    if (val === null || val === undefined) {
        return ''
    }
    let currentLang = uni.getLocale()
    // console.log('语言格式化', currentLang, val)
    // 默认值
    const defaultRes = val.cn || val.zh || ''
    if (!currentLang) {
        return defaultRes
    }
    currentLang = currentLang.toLowerCase()
    // 中文特殊处理
    if (currentLang == 'cn' || currentLang.startsWith('zh')) {
        return val.cn || val.zh || ''
    }
    Object.keys(val).forEach((key) => {
        if (currentLang.toLowerCase().startsWith(key.toLowerCase())) {
            return val[key]
        }
    })
    return defaultRes
}

// 清空前后空格
export const trim = (val: string) => {
    return val.replace(/(^\s*)|(\s*$)/g, '')
}

// 距离格式化
export const distanceFormat = (val: any) => {
    console.log('distanceFormat', val)
    if (val) {
        val = Number(val)
        if (val < 1000) {
            return val.toFixed() + 'm'
        } else {
            return (val / 1000).toFixed(2) + 'km'
        }
    } else {
        return ''
    }
}

// 连接格式化
export const joinFormat = (separate: any = '/', ...val: any[]) => {
    let res = ''
    val.forEach((item, index) => {
        res += item ? `${item}${index != val.length - 1 ? separate : ''}` : ''
    })
    // 处理最后一个元素为空的情况
    if (res.lastIndexOf(separate) == res.length - 1) {
        res = res.substring(0, res.length - 1)
    }
    // console.log('连接格式化', res, val)
    return res
}

/**
 * 页面跳转
 * @param url          跳转链接   /pages/home/index
 * @pamra query        跳转参数   { id: 1 }
 * @param navigateType  跳转类型  navigateTo | reLaunch | redirectTo | switchTab
 */
export const jump = (
    url: string,
    query?: Record<string, any> | null,
    navigateType: 'navigateTo' | 'reLaunch' | 'redirectTo' | 'switchTab' = 'navigateTo'
) => {
    // console.log('jump', url, query, navigateType)
    let jumpUrl = ''
    // 判断是否有参数
    if (query && Object.keys(query).length > 0) {
        if (url.includes('?')) {
            jumpUrl = `${url}&${objectToQuery(query)}`
        } else {
            jumpUrl = `${url}?${objectToQuery(query)}`
        }
    } else {
        jumpUrl = url
    }
    // 根据导航类型进行跳转
    switch (navigateType) {
        // 保留当前页面，跳转到应用内的某个页面，使用uni.navigateBack可以返回到原页面：需要跳转的应用内非 tabBar 的页面的路径 , 路径后可以带参数。参数与路径之间使用?分隔，参数键与参数值用=相连，不同参数用&分隔；如 'path?key=value&key2=value2'，path为下一个页面的路径，下一个页面的onLoad函数可得到传递的参数
        case 'navigateTo':
            uni.navigateTo({ url: jumpUrl })
            break
        // 关闭所有页面，打开到应用内的某个页面：需要跳转的应用内页面路径 , 路径后可以带参数。参数与路径之间使用?分隔，参数键与参数值用=相连，不同参数用&分隔；如 'path?key=value&key2=value2'，如果跳转的页面路径是 tabBar 页面则不能带参数
        case 'reLaunch':
            uni.reLaunch({ url: jumpUrl })
            break
        // 关闭当前页面，跳转到应用内的某个页面：需要跳转的应用内非 tabBar 的页面的路径，路径后可以带参数。参数与路径之间使用?分隔，参数键与参数值用=相连，不同参数用&分隔；如 'path?key=value&key2=value2'
        case 'redirectTo':
            uni.redirectTo({ url: jumpUrl })
            break
        // 跳转到 tabBar 页面，并关闭其他所有非 tabBar 页面：要跳转的 tabBar 页面的路径（需在 pages.json 的 tabBar 字段定义的页面），路径后不能带参数
        case 'switchTab':
            uni.switchTab({ url: url })
            break
        default:
            console.warn('Unknown navigateType:', navigateType)
    }
}

/**
 * 返回上一页
 */
export const backup = () => {
    uni.navigateBack()
}

/**
 * 打电话
 * @param item
 */
export const callPhone = async (val: string, hintText?: string) => {
    if (val) {
        // 权限提示
        // #ifdef APP-PLUS
        const authority = UseAuthority()
        const result = await authority.requestPermissions('CALL_PHONE')
        if (result !== 1) return
        // #endif
        uni.makePhoneCall({
            phoneNumber: val
        })
    } else {
        if (hintText) {
            // uni.$u.toast(hintText)
            uni.showToast({
                title: hintText,
                icon: 'none'
            })
        }
    }
}

/**
 * 判断是否含有token
 * 有就返回token 否则 为 ""
 *
 * @returns {token}
 */
export const haveToken = () => {
    return uni.getStorageSync('app_token') || ''
}

/**
 * 判断有没有tokne  没有就跳转登录页
 *
 * false为未登录
 * true 为已经登录
 *
 */
export const checkToken = () => {
    if (haveToken() === '') {
        jump('/pages/login/sign-in')
        return false
    }
    return true
}

/**
 * 复制功能
 */
export const copy = (text: string, tips: string) => {
    console.log('copy', text)
    uni.setClipboardData({
        data: text,
        success: () => {
            uni.showToast({
                title: tips,
                icon: 'none'
            })
        }
    })
}

/**
 * 获取url参数
 * @param url
 * @param paraName
 */
export const getQueryString = (url: string, paraName: string) => {
    const arrObj = url.split('?')
    if (arrObj.length > 1) {
        const arrPara = arrObj[1].split('&')
        let arr
        for (let i = 0; i < arrPara.length; i++) {
            arr = arrPara[i].split('=')
            // eslint-disable-next-line eqeqeq
            if (arr != null && arr[0] == paraName) {
                return arr[1]
            }
        }
        return ''
    } else {
        return ''
    }
}

/**
 * 获取url参数
 */
export const getUrlParams = (url: string) => {
    // 通过 ? 分割获取后面的参数字符串
    const urlStr = url.split('?')[1]
    // 创建空对象存储参数
    const obj: {
        [key: string]: string
    } = {}
    // 再通过 & 将每一个参数单独分割出来
    const paramsArr = urlStr.split('&')
    for (let i = 0, len = paramsArr.length; i < len; i++) {
        // 再通过 = 将每一个参数分割为 key:value 的形式
        const arr = paramsArr[i].split('=')
        obj[arr[0]] = arr[1]
    }
    return obj
}
// 类型-图片
export const typeImage = ['gif', 'png', 'jpg', 'jpeg', 'webp', 'svg', 'psd', 'bmp', 'tif']
// 类型-视频
export const typeVideo = [
    'swf',
    'avi',
    'flv',
    'mpg',
    'rm',
    'mov',
    'wav',
    'asf',
    '3gp',
    'mkv',
    'rmvb',
    'mp4'
]

// 判断是否是图片
export const isImage = (url: string) => {
    return typeImage.includes(url.split('.').pop()!.toLowerCase())
}
// 判断是否是视频
export const isVideo = (url: string) => {
    return typeVideo.includes(url.split('.').pop()!.toLowerCase())
}

/**
 * 查看大图
 * @param url
 */
export const viewLargeImg = (url: string) => {
    const extension = url.split('.').pop()!.toLowerCase()
    let pattern
    // 根据文件扩展名判断是图片还是视频
    if (typeImage.includes(extension)) {
        // 图片文件，移除后缀中的 "_[数字]" 或 "_thumb"
        pattern = new RegExp(`(_\\d+|_thumb)\\.(${typeImage.join('|')})$`, 'i')
    } else if (typeVideo.includes(extension)) {
        // 视频文件，移除后缀中的 "_compress"
        pattern = new RegExp(`(_compress)\\.(${typeVideo.join('|')})$`, 'i')
    } else {
        // 如果不是图片或视频，不做处理直接返回原URL
        return url
    }

    // 替换匹配到的模式为相应的扩展名，即删除特定的后缀
    return url.replace(pattern, '.$2')
}

/**
 * 获取网络资源
 * @param name
 */
export const getImg = (name: string) => {
    // 引入网络资源 img/tabbar/add.png
    return name.includes('http') ? name : 'https://pandauke.oss-cn-guangzhou.aliyuncs.com/static' + name
}

export const getImgUrl = (name: string) => {
    if (!name) {
        return getImg('/img/logo/logo.png')
    }

    return name.includes('http') ? name : 'https://pandauke.oss-cn-guangzhou.aliyuncs.com/' + name
}

// 获取状态栏高度
export const getStatusBarHeight = () => {
    const res = uni.getSystemInfoSync()
    return res.statusBarHeight
}

//获取微信胶囊高度
export const getMenuButtonTop = (): number => {
    const res = uni.getMenuButtonBoundingClientRect()
    return res.top
}

// 获取页面高度
export const getWindowHeight = () => {
    const res = uni.getSystemInfoSync()

    console.log('res', res.windowHeight)
    return res.windowHeight
}

/**
 *  百分比 rpx 转 px
 */
export function toPx(num: any) {
    if (typeof num === 'string') {
        if (num.indexOf('px') !== -1) {
            if (num.indexOf('rpx') !== -1) {
                // "10rpx"
                num = num.replace('rpx', '')
            } else if (num.indexOf('upx') !== -1) {
                // "10upx"
                num = num.replace('upx', '')
            } else {
                // "10px"
                return Number(num.replace('px', ''))
            }
        } else if (num.indexOf('%') !== -1) {
            // 传百分比,则相对于windowHeight,传"10%"则等于windowHeight的10%
            const rate = Number(num.replace('%', '')) / 100
            return uni.getSystemInfoSync().windowHeight * rate
        }
    }
    return num ? uni.upx2px(Number(num)) : 0
}
